#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import os
import shutil
import sys
import tempfile

execfile(os.path.join(sys.path[0], "framework.py"))

from unittest import TestCase, TestLoader, TextTestRunner
from oriolus.docker.docker import Docker, DockerError
from oriolus.docker.repos.repository import Repository
from oriolus.docker.storages.filestorage import FileStorage
from oriolus.docker.tests.mocks import MockRepository
from oriolus.pith.packets.packet import Status, FilePacket

class TestDocker(TestCase):

    def setUp(self):
        self.__test_packet = "./testdata/testpackets/test_packet-1.2.3.4.zip.ori"
        self.__test_packet2 = "./testdata/testpackets/test_packet2-2.3.4.5.zip.ori"
        self.__test_packet3 = "./testdata/testpackets/test_packet-2.3.4.5.zip.ori"
        self.__test_packet4 = "./testdata/testpackets/test_packet3-1.2.3.4.zip.ori"
        self.__test_packet5 = "./testdata/testpackets/test_packet4-1.2.3.4.zip.ori"
        self.__test_packet_with_relative_path = "./testdata/testpackets/test_packet_with_relative_path-1.2.3.4.zip.ori"

    def test_docker_install2_0(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(packet_path=self.__test_packet)
            self.assertEqual(1, len(storage.entries))
            self.assertEqual("test_packet-1.2.3.4", storage.entries[0].name)
            self.assertEqual(Status.INSTALLED, storage.entries[0].status)
            self.assertFilesInstalled(rep_dir)
        finally:
            shutil.rmtree(rep_dir)

    def test_docker_install2_1(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(packet_path=self.__test_packet, status=Status.INSTALLING)
            self.assertEqual(1, len(storage.entries))
            self.assertEqual("test_packet-1.2.3.4", storage.entries[0].name)
            self.assertEqual(Status.INSTALLED, storage.entries[0].status)
            self.assertFilesInstalled(rep_dir)
        finally:
            shutil.rmtree(rep_dir)

    def test_docker_install2_2(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(packet_path=self.__test_packet, status=Status.INSTALLING_AS_DEPENDENCY)
            self.assertEqual(1, len(storage.entries))
            self.assertEqual("test_packet-1.2.3.4", storage.entries[0].name)
            self.assertEqual(Status.INSTALLED_AS_DEPENDENCY, storage.entries[0].status)
            self.assertFilesInstalled(rep_dir)
        finally:
            shutil.rmtree(rep_dir)
            
    def assertFilesInstalled(self, rep_dir):
        scripts = ["preinstall.py", "install.py", "postinstall.py"]
        expected_entry_name = "test_packet-1.2.3.4.ori.entry"
        self.assertTrue(os.path.exists(os.path.join(rep_dir, expected_entry_name)))
        [self.assertTrue(os.path.exists(os.path.join(rep_dir, "test_packet-1.2.3.4", script_path))) for script_path in scripts]
            
    def test_docker_install_to_relative_path(self):
        rep_dir = tempfile.mkdtemp()
        base_path = tempfile.mkdtemp()
            
        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(packet_path=self.__test_packet_with_relative_path, base_path = base_path, status=Status.INSTALLING)
            self.assertEqual(1, len(storage.entries))
            self.assertEqual("test_packet_with_relative_path-1.2.3.4", storage.entries[0].name)
            self.assertEqual(Status.INSTALLED, storage.entries[0].status)
            self.assertTrue(os.path.exists(os.path.join(base_path, "TestDirectory")))
            self.assertTrue(os.path.exists(os.path.join(base_path, "TestDirectory", "test_file.xml")))
            
            expected_entry_name = "test_packet_with_relative_path-1.2.3.4.ori.entry"
            self.assertTrue(os.path.exists(os.path.join(rep_dir, expected_entry_name)))
            
            scripts = ["installation.xml", "install.py", "remove.py"]
            [self.assertTrue(os.path.exists(os.path.join(rep_dir, "test_packet_with_relative_path-1.2.3.4", script_path))) for script_path in scripts]
            
            self.assertEqual(1, len(os.listdir(base_path)))
             
        finally:
            shutil.rmtree(rep_dir)
            shutil.rmtree(base_path)

    def test_docker_install_as_dep_then_normal(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(packet_path=self.__test_packet, status=Status.INSTALLING_AS_DEPENDENCY)
            self.assertEqual(1, len(storage.entries))
            self.assertEqual("test_packet-1.2.3.4", storage.entries[0].name)
            self.assertEqual(Status.INSTALLED_AS_DEPENDENCY, storage.entries[0].status)
            self.assertFilesInstalled(rep_dir)

            docker.install(packet_path=self.__test_packet, status=Status.INSTALLING)
            self.assertEqual(1, len(storage.entries))
            self.assertEqual("test_packet-1.2.3.4", storage.entries[0].name)
            self.assertEqual(Status.INSTALLED, storage.entries[0].status)
            
        finally:
            shutil.rmtree(rep_dir)

    def test_docker_repeated_install(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(packet_path=self.__test_packet)
            self.assertEqual(1, len(storage.entries))
            self.assertEqual("test_packet-1.2.3.4", storage.entries[0].name)
            self.assertEqual(Status.INSTALLED, storage.entries[0].status)
            self.assertFilesInstalled(rep_dir)
            
            self.assertRaises(DockerError, docker.install, packet_path=self.__test_packet)
        finally:
            shutil.rmtree(rep_dir)

    def test_docker_install4(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            self.assertRaises(DockerError, docker.install, packet_path=self.__test_packet2)
        finally:
            shutil.rmtree(rep_dir)
    
    def test_docker_install5(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            
            docker.install(packet_path=self.__test_packet)
            self.assertEqual(1, len(storage.entries))
            self.assertEqual("test_packet-1.2.3.4", storage.entries[0].name)
            self.assertEqual(Status.INSTALLED, storage.entries[0].status)
            
            docker.install(packet_path=self.__test_packet2)
            self.assertEqual(2, len(storage.entries))
            self.assertTrue("test_packet2-2.3.4.5" in [entry.name for entry in storage.entries])
            [self.assertEqual(Status.INSTALLED, entry.status) for entry in storage.entries]
        finally:
            shutil.rmtree(rep_dir)
            
    def test_docker_install6(self):
        docker = Docker(MockRepository())
        self.assertRaises(DockerError, docker.install, "")
        
    def test_docker_install7(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))        
            self.assertRaises(DockerError, docker.install, packet_path=self.__test_packet4)
        finally:
            shutil.rmtree(rep_dir)
        
    def test_docker_install8(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))        
            self.assertRaises(DockerError, docker.install, packet_path=self.__test_packet5)
        finally:
            shutil.rmtree(rep_dir)
            
    def test_docker_remove1(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(self.__test_packet)
            self.assertEqual(1, len(storage.entries))
            name = storage.entries[0].name
            self.assertEqual("test_packet-1.2.3.4", name)
            
            docker.remove(packet_name=name)
            self.assertEqual(0, len(storage.entries))
            self.assertFalse(os.listdir(rep_dir))
        finally:
            shutil.rmtree(rep_dir)

    def test_docker_remove2(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            name = "test_packet-1.2.3.4"
            
            self.assertRaises(DockerError, docker.remove, packet_name=name)
        finally:
            shutil.rmtree(rep_dir)
    
    def test_docker_remove3(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(self.__test_packet)
            docker.install(self.__test_packet2)
            self.assertEqual(2, len(storage.entries))

            self.assertRaises(DockerError, docker.remove, packet_name="test_packet-1.2.3.4")
        finally:
            shutil.rmtree(rep_dir)

    def test_docker_remove4(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(self.__test_packet)
            docker.install(self.__test_packet2)
            self.assertEqual(2, len(storage.entries))

            docker.remove(packet_name="test_packet2-2.3.4.5")
            self.assertEqual(1, len(storage.entries))
            docker.remove(packet_name="test_packet-1.2.3.4")
            self.assertEqual(0, len(storage.entries))
            self.assertFalse(os.listdir(rep_dir))
        finally:
            shutil.rmtree(rep_dir)

    def test_docker_remove5(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(self.__test_packet)
            docker.install(self.__test_packet2)
            self.assertEqual(2, len(storage.entries))

            docker.remove(packet_name="test_packet2-2.3.4.5")
            self.assertEqual(1, len(storage.entries))
            docker.remove(packet_name="test_packet-1.2.3.4")
            self.assertEqual(0, len(storage.entries))
            self.assertFalse(os.listdir(rep_dir))
        finally:
            shutil.rmtree(rep_dir)
           
    def test_docker_remove6(self):
        docker = Docker(MockRepository())
        self.assertRaises(DockerError, docker.remove, "")
        
    def test_docker_remove7(self):
        docker = Docker(MockRepository())
        self.assertRaises(DockerError, docker.remove, [])
        
    def test_docker_remove8(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(self.__test_packet)
            self.assertEqual(1, len(storage.entries))

            storage2 = FileStorage(rep_dir)
            docker2 = Docker(Repository(storage2))
            docker2.remove(packet_name="test_packet-1.2.3.4")
            self.assertEqual(0, len(storage.entries))
            self.assertFalse(os.listdir(rep_dir))
        finally:
            shutil.rmtree(rep_dir)
            
    def test_docker_remove9(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(self.__test_packet)
            docker.install(self.__test_packet2)
            self.assertEqual(2, len(storage.entries))

            self.assertRaises(DockerError, docker.remove, packet_name="test_packet-1.2.3.4")
        finally:
            shutil.rmtree(rep_dir)

    def test_docker_empty_list_command(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            result = docker.search(get_all=True)
            self.assertEqual([], result)
        finally:
            shutil.rmtree(rep_dir)

    def test_docker_list_command1(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(self.__test_packet)
            result = docker.search(get_all=True)
            self.assertEqual(1, len(result))
            expectedPacket = FilePacket(self.__test_packet, status=Status.INSTALLED)
            actualPacket = result[0]
            self.assertEqual(expectedPacket.status, actualPacket.status)
            self.assertEqual(expectedPacket.name, actualPacket.name)
        finally:
            shutil.rmtree(rep_dir)
            
    def test_docker_list_command2(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(self.__test_packet)
            docker.install(self.__test_packet2)
            actualPackets = docker.search(get_all=True)
            self.assertEqual(2, len(actualPackets))
            self.assertNotEqual(actualPackets[0].name, actualPackets[1].name)
                
        finally:
            shutil.rmtree(rep_dir)
                
    def test_docker_list_command3(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(self.__test_packet)
            docker.install(self.__test_packet3)
            actualPackets = docker.search(name="test_packet")
            self.assertEqual(2, len(actualPackets))
            self.assertNotEqual(actualPackets[0].name, actualPackets[1].name)
            actualPackets = docker.search(name="test_packet")
            self.assertEqual(2, len(actualPackets))
            self.assertNotEqual(actualPackets[0].name, actualPackets[1].name)
            actualPackets = docker.search(name="test_packet-2.3.4.5")
            self.assertEqual(0, len(actualPackets))
            actualPackets = docker.search(full_name="test_packet-2.3.4.5")
            self.assertEqual(1, len(actualPackets))
        finally:
            shutil.rmtree(rep_dir)

    def test_docker_list_status_command2(self):
        rep_dir = tempfile.mkdtemp()

        try:
            storage = FileStorage(rep_dir)
            self.assertEqual([], storage.entries)
            docker = Docker(Repository(storage))
            docker.install(self.__test_packet)
            docker.install(self.__test_packet2)
            docker.install(self.__test_packet3)
            actualPackets = docker.search(get_all=True)
            self.assertEqual(3, len(actualPackets))
            actualPackets = docker.search(status=Status.INSTALLED, name="test_packet2")
            self.assertEqual(1, len(actualPackets))

        finally:
            shutil.rmtree(rep_dir)

if __name__ == "__main__":
    suite = TestLoader().loadTestsFromTestCase(TestDocker)
    TextTestRunner(verbosity=2).run(suite)